package cn.iocoder.yudao.module.iot.gateway.protocol.tcp.router;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
import cn.iocoder.yudao.module.iot.gateway.codec.IotDeviceMessageCodec;
import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.detector.ProtocolDetector;
import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.manager.IotTcpConnectionManager;
import cn.iocoder.yudao.module.iot.gateway.service.device.IotDeviceService;
import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.NetSocket;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;

/**
 * 通用TCP上行消息处理器
 */
@Slf4j
public class GenericTcpUpstreamHandler implements Handler<NetSocket> {

    private final ProtocolDetector protocolDetector;
    private final Map<String, IotDeviceMessageCodec> codecRegistry;
    private final IotDeviceMessageService deviceMessageService;
    private final IotDeviceService deviceService;
    private final IotTcpConnectionManager connectionManager;

    public GenericTcpUpstreamHandler(ProtocolDetector protocolDetector,
                                     Map<String, IotDeviceMessageCodec> codecRegistry,
                                     IotDeviceMessageService deviceMessageService,
                                     IotDeviceService deviceService,
                                     IotTcpConnectionManager connectionManager) {
        this.protocolDetector = protocolDetector;
        this.codecRegistry = codecRegistry;
        this.deviceMessageService = deviceMessageService;
        this.deviceService = deviceService;
        this.connectionManager = connectionManager;
    }

    @Override
    public void handle(NetSocket socket) {
        String clientId = IdUtil.simpleUUID();
        log.debug("[handle][设备连接, 客户端 ID: {}, 地址: {}]", clientId, socket.remoteAddress());

        // 设置异常和关闭处理器
        socket.exceptionHandler(ex -> {
            log.warn("[handle][连接异常, 客户端 ID: {}, 地址: {}]", clientId, socket.remoteAddress());
            cleanupConnection(socket);
        });
        socket.closeHandler(v -> {
            log.debug("[handle][连接关闭, 客户端 ID: {}, 地址: {}]", clientId, socket.remoteAddress());
            cleanupConnection(socket);
        });

        // 设置消息处理器
        socket.handler(buffer -> {
            try {
                processMessage(clientId, buffer, socket);
            } catch (Exception e) {
                log.error("[handle][消息解码失败, 断开连接, 客户端 ID: {}, 地址: {}, 错误: {}]",
                        clientId, socket.remoteAddress(), e.getMessage());
                cleanupConnection(socket);
                socket.close();
            }
        });
    }

    /**
     * 处理消息
     */
    private void processMessage(String clientId, Buffer buffer, NetSocket socket) throws Exception {
        // 1. 基础检查
        if (buffer == null || buffer.length() == 0) {
            return;
        }

        // 2. 检测协议类型
        String protocolType = detectProtocolType(buffer, socket);

        // 3. 获取对应的编解码器
        IotDeviceMessageCodec codec = codecRegistry.get(protocolType);
        if (codec == null) {
            throw new Exception("未找到协议类型对应的编解码器: " + protocolType);
        }

        // 4. 解码消息
        IotDeviceMessage message = codec.decode(buffer.getBytes());
        if (message == null) {
            throw new Exception("解码后消息为空");
        }

        // 5. 处理消息（这里简化处理, 实际需要根据消息类型路由处理）
        log.info("[processMessage][接收到消息, 客户端 ID: {}, 协议类型: {}, 消息: {}]",
                clientId, protocolType, message.toString());
    }

    /**
     * 检测协议类型
     */
    private String detectProtocolType(Buffer buffer, NetSocket socket) {
        // 1. 如果已认证, 优先使用缓存的协议类型
        IotTcpConnectionManager.ConnectionInfo connectionInfo = connectionManager.getConnectionInfo(socket);
        if (connectionInfo != null && connectionInfo.isAuthenticated() &&
                StrUtil.isNotBlank(connectionInfo.getCodecType())) {
            return connectionInfo.getCodecType();
        }

        // 2. 通过协议检测器检测协议类型
        return protocolDetector.detectProtocol(buffer.getBytes());
    }

    /**
     * 清理连接
     */
    private void cleanupConnection(NetSocket socket) {
        try {
            connectionManager.unregisterConnection(socket);
        } catch (Exception e) {
            log.error("[cleanupConnection][清理连接失败] {}", ExceptionUtil.stacktraceToOneLineString(e));
        }
    }
}
